package cn.mhome.merchant.dao.spring.data.repository;

import java.io.Serializable;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;


/**
 * 
 * @author zhouwei
 *
 * @param <T>
 * @param <ID>
 */
public class CriteriaRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID>
		implements CriteriaRepository<T, ID> {
	private Class<T> domainClass;
	private EntityManager entityManager;
	
	public CriteriaRepositoryImpl(Class<T> domainClass, EntityManager em) {
		super(domainClass, em);
		this.entityManager = em;
		this.domainClass = domainClass;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<T> findByCriteria(Criteria criteria, Pageable page) {
		// 暂不处理having groupby等子句
		BasicQuery sqlAnnotation = domainClass.getAnnotation(BasicQuery.class);
		if (sqlAnnotation == null) {
			throw new RuntimeException("CriteriaRepositoryImpl.findByCriteria run error, "
					+ "domainClass must have BasicQuery annotation");
		}
		
		StringBuffer sbSql = new StringBuffer();
		
		String sqlBasic = sqlAnnotation.value();
		String sqlWhere = criteria.getQueryExpression();

		if (sqlBasic.indexOf("$$where$$") > 0) {
			if ((sqlWhere != null) && (sqlWhere.isEmpty() == false)) {
				sqlBasic = sqlBasic.replaceFirst("\\$\\$where\\$\\$", sqlWhere);
			} else {
				sqlBasic = sqlBasic.replaceFirst("\\$\\$where\\$\\$", "");
			}
			sbSql.append(sqlBasic);
		} else {
			sbSql.append(sqlBasic);
            if ((sqlWhere != null) && (sqlWhere.isEmpty() == false)) {
                sbSql.append(" where ");
                sbSql.append(sqlWhere);
            }
		}

		sbSql.append(" ");
		sbSql.append(PageableHelper.getSqlExpressionForOrderBy(page));
		sbSql.append(" ");
		sbSql.append(PageableHelper.getSqlExpressionForLimit(page));
        SQLQuery query = entityManager.unwrap(Session.class).createSQLQuery(sbSql.toString()).addEntity(this.domainClass);
		//Query query = entityManager.createNativeQuery(sbSql.toString(), this.domainClass);
		Map<String, Object> params = criteria.getParameterAndValue();
		for (String paramName : params.keySet()) {
			query.setParameter(paramName, params.get(paramName));
		}
		return (List<T>) query.list();
	}

	@Override
	public long countByCriteria(Criteria criteria) {
		BasicQuery sqlAnnotation = domainClass.getAnnotation(BasicQuery.class);
		if (sqlAnnotation == null) {
			throw new RuntimeException("CriteriaRepositoryImpl.findByCriteria run error, "
					+ "domainClass must have BasicQuery annotation");
		}
		
		StringBuffer sbSql = new StringBuffer();
		
		String sqlBasic = sqlAnnotation.value();
		Pattern pat = Pattern.compile("select\\x20(.*?)\\x20from", Pattern.CASE_INSENSITIVE);
		Matcher mat = pat.matcher(sqlBasic);
		String sqlBasicForCount = mat.replaceFirst("select count(*) from");

		sbSql.append(sqlBasicForCount);
		String sqlWhere = criteria.getQueryExpression();
		if ((sqlWhere != null) && (sqlWhere.isEmpty() == false)) {
			sbSql.append(" where ");
			sbSql.append(sqlWhere);
		}

		Query query = entityManager.createNativeQuery(sbSql.toString());
		Map<String, Object> params = criteria.getParameterAndValue();
		for (String paramName : params.keySet()) {
			query.setParameter(paramName, params.get(paramName));
		}
		
		BigInteger result = (BigInteger)query.getSingleResult();
		return result.longValue();
	}

//	/**
//	 * 多表查询不分页
//	 */
//	@Override
//	public List<?> findBySqlForList(String sql, Map<String,Object> params,Class<? extends EntityMap> clazz) {
//		Session session=entityManager.unwrap(Session.class);
//		org.hibernate.Query query = session.createSQLQuery(sql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
//		for(Map.Entry<String,Object> entry : params.entrySet()){
//			query.setParameter(entry.getKey(), entry.getValue());
//		}
//		List<Map<Object,Object>>  list = query.list();
//		List<?> entitys = (List<?>) EntityMapper.mapperList(list, clazz);
//		return entitys;
//	}
//
//	/**
//	 * 多表查询分页
//	 */
//	@Override
//	public Pager findBySqlForPage(String selectSql, String fromSql,
//			Map<String, Object> params, Class<? extends EntityMap> clazz,
//			int page, int pagesize) {
//		Session session = entityManager.unwrap(Session.class);
//		Pager pager = new Pager(page,pagesize);
//		org.hibernate.Query pageQuery = session.createSQLQuery("SELECT count(1) "+fromSql);
//		org.hibernate.Query dataQuery = session.createSQLQuery(selectSql+fromSql).setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
//		dataQuery.setFirstResult(pager.getFirstResult());
//		dataQuery.setMaxResults(pagesize);
//		for(Map.Entry<String,Object> entry : params.entrySet()){
//			pageQuery.setParameter(entry.getKey(),entry.getValue());
//			dataQuery.setParameter(entry.getKey(),entry.getValue());
//		}
//		
//		BigInteger count = (BigInteger)pageQuery.uniqueResult();
//		if(count != null){
//			pager.setTotalResults(count.intValue());
//			if(count.intValue() == 0){
//				return pager;
//			}
//		}
//		
//		List<Map<Object,Object>>  list = dataQuery.list();
//		List<?> entitys = (List<?>) EntityMapper.mapperList(list,clazz);
//		pager.setData(entitys);
//		return pager;
//	}
//
//	
//	/**
//	 * 支持单表分页  必须使用hql
//	 */
//	@Override
//	public Pager findByHqlForPage(String Hql, Map<String, Object> params,
//			int page, int pagesize) {
//		
//		Pager pager = new Pager(page,pagesize);
//		Query totalQuery = this.entityManager.createQuery("select count(*)"+ Hql);
//		Query dataQuery = this.entityManager.createQuery(Hql);
//		dataQuery.setFirstResult(pager.getFirstResult());
//		dataQuery.setMaxResults(pagesize);
//		for (Map.Entry<String,Object> entry : params.entrySet()){
//			totalQuery.setParameter(entry.getKey(),entry.getValue());
//			dataQuery.setParameter(entry.getKey(),entry.getValue());
//		}
//		Long total = (Long) totalQuery.getSingleResult();
//		List<T> dataList = dataQuery.getResultList();
//		pager.setData(dataList);
//		pager.setTotalResults(total.intValue());
//		return pager;
//	}
//
//	@Override
//	public List<T> findByHqlForList(String Hql, Map<String, Object> params) {
//		Query dataQuery = this.entityManager.createQuery(Hql);
//		for (Map.Entry<String,Object> entry : params.entrySet()){
//			dataQuery.setParameter(entry.getKey(),entry.getValue());
//		}
//		return dataQuery.getResultList();
//	}
	
	public void saveSelf(List<T> list,int count) {
		int i=0;
		count = count == 0?500:count;
		for(T t:list){
			entityManager.persist(t);
			if(i%count==0){
				entityManager.flush();
			}
			i++;
		}
		entityManager.flush();
	}
}
